﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;

using ApproveFlowEngine.Enums.Core;

using Volo.Abp;

namespace ApproveFlowEngine.Core.Base
{
    [NotMapped]
    public abstract class WorkNodeComplex : WorkNode
    {
        #region Internal Constructors

        internal WorkNodeComplex( Guid id) : base( id)
        {
            IsLeaf = false;
        }

        #endregion Internal Constructors



        #region Protected Constructors

        protected WorkNodeComplex()
        {
            IsLeaf = false;
        }

        #endregion Protected Constructors



        #region Public Properties

        [NotMapped]
        public int ActivityCount => Children.Count(c => c.Status is Enums.Core.ApproveNodeStatus.Activity);

        [NotMapped]
        public WorkNode? Head { get; set; }

        [NotMapped]
        public int NoneCount => Children.Count(c => c.Status is Enums.Core.ApproveNodeStatus.None);

        [NotMapped]
        public int PassCount => Children.Count(c => c.Status is Enums.Core.ApproveNodeStatus.Pass);

        [NotMapped]
        public int RejectCount => Children.Count(c => c.Status is Enums.Core.ApproveNodeStatus.Reject);

        [NotMapped]
        public WorkNode? Tail { get; set; }

        #endregion Public Properties



        #region Public Methods

        public virtual WorkNode AddChild(WorkNode child)
        {
            child.Parent = this;
            child.Index = Children.Count + 1;
            if (Head is null || Tail is null)
            {
                Head = child;
                Tail = child;
            }
            else
            {
                Tail.Next = child;
                child.Before = Tail;
                Tail = child;
            }
            Children.Add(child);
            return this;
        }

        public virtual WorkNode AddChild<T>(Func<WorkNode, T> func) where T : WorkNode
        {
            var child = func(this);
            return AddChild(child);
        }

        public override bool ExecApprove(Guid nodeId, ApproveNodeStatus status)
        {
            if (nodeId == Id)
            {
                throw new BusinessException($"【{nodeId}】节点ID错误！");
            }
            var result = false;
            foreach (var item in Children)
            {
                result = item.Approve(nodeId, status);
                if (result)
                {
                    break;
                }
            }
            return result;
        }

        public List<WorkNode> GetAllLeaf()
        {
            return GetChildrens(true);
        }

        public List<WorkNode> GetAllNodes()
        {
            return GetChildrens();
        }

        public override void Init()
        {
            base.Init();
            foreach (var item in Children)
            {
                item.Init();
            }
        }

        #endregion Public Methods



        #region Protected Methods

        protected List<WorkNode> GetChildrens(bool isOnlyLeaf = false)
        {
            var result = new List<WorkNode>();
            var queue = new Queue<WorkNode>();
            queue.Enqueue(this);
            while (queue.TryDequeue(out var node))
            {
                if (node.IsLeaf)
                {
                    result.Add(node);
                }
                else
                {
                    foreach (var item in ((WorkNodeComplex)node).Children)
                    {
                        if (!isOnlyLeaf ^ item.IsLeaf)
                        {
                            result.Add(item);
                        }
                        queue.Enqueue(item);
                    }
                }
            }
            return result;
        }

        #endregion Protected Methods
    }
}